﻿namespace Microsoft.VisualStudio.ServiceModel.DomainServices.Tools
{
    using Microsoft.ServiceModel.DomainServices.Tools;
    using System;
    using System.Collections.Generic;
    using System.Data.Linq;
    using System.Data.Objects;
    using System.Globalization;
    using System.Linq;
    using System.Reflection;
    using System.Web.Hosting;

    internal class BusinessLogicModel : MarshalByRefObject, IRegisteredObject, IDisposable
    {
        private Microsoft.VisualStudio.ServiceModel.DomainServices.Tools.BusinessLogicData _businessLogicData;
        private List<BusinessLogicContext> _contexts;
        private Action<string> _logger;

        public BusinessLogicModel() : this(delegate (string s) {
        })
        {
        }

        internal BusinessLogicModel(Action<string> logger)
        {
            if (logger == null)
            {
                throw new ArgumentNullException("logger");
            }
            this._logger = logger;
        }

        public void Dispose()
        {
            this._contexts = null;
        }

        public GeneratedCode GenerateBusinessLogicClass(ContextData contextData, string className, string namespaceName, string rootNamespace)
        {
            BusinessLogicContext context = this._contexts.SingleOrDefault<BusinessLogicContext>(c => c.ContextData.ID == contextData.ID);
            if (context == null)
            {
                return new GeneratedCode();
            }
            return context.GenerateBusinessLogicClass(this.Language, className, namespaceName, rootNamespace);
        }

        public GeneratedCode GenerateMetadataClasses(ContextData contextData, string rootNamespace, string optionalSuffix)
        {
            BusinessLogicContext context = this._contexts.Single<BusinessLogicContext>(c => c.ContextData.ID == contextData.ID);
            if (context == null)
            {
                return new GeneratedCode(string.Empty, new string[0]);
            }
            return context.GenerateMetadataClasses(this.Language, rootNamespace, optionalSuffix);
        }

        internal ContextData[] GetContextDataItems()
        {
            if (this._contexts == null)
            {
                List<Assembly> loadedAssemblies = new List<Assembly>();
                this._contexts = new List<BusinessLogicContext>();
                this.LoadAssemblies(this.BusinessLogicData.AssemblyPaths, loadedAssemblies);
                this.LoadAssemblies(this.BusinessLogicData.ReferenceAssemblyPaths, loadedAssemblies);
                List<Type> list2 = new List<Type>();
                HashSet<string> set = new HashSet<string>(this.BusinessLogicData.ContextTypeNames);
                foreach (string str in this.BusinessLogicData.ContextTypeNames)
                {
                    Type item = Type.GetType(str, false);
                    if (item != null)
                    {
                        list2.Add(item);
                        set.Remove(item.AssemblyQualifiedName);
                    }
                }
                foreach (Assembly assembly in loadedAssemblies)
                {
                    if (set.Count > 0)
                    {
                        foreach (Type type2 in AssemblyUtilities.GetExportedTypes(assembly, this._logger).ToArray<Type>())
                        {
                            if ((set.Count > 0) && set.Contains(type2.AssemblyQualifiedName))
                            {
                                list2.Add(type2);
                                set.Remove(type2.AssemblyQualifiedName);
                            }
                        }
                    }
                }
                this._contexts.Add(new BusinessLogicContext(null, Resources.BusinessLogic_Class_Empty_Class_Name));
                foreach (Type type3 in list2)
                {
                    if (typeof(DataContext).IsAssignableFrom(type3))
                    {
                        this._contexts.Add(new LinqToSqlContext(type3));
                    }
                    else if (typeof(ObjectContext).IsAssignableFrom(type3))
                    {
                        this._contexts.Add(new LinqToEntitiesContext(type3));
                    }
                    else
                    {
                        Type dbContextTypeReference = DbContextUtilities.GetDbContextTypeReference(type3);
                        if ((dbContextTypeReference != null) && dbContextTypeReference.IsAssignableFrom(type3))
                        {
                            this._contexts.Add(new LinqToEntitiesDbContext(type3));
                        }
                        else
                        {
                            this._logger(string.Format(CultureInfo.CurrentCulture, Resources.BusinessLogicClass_InvalidContextType, new object[] { type3.FullName }));
                        }
                    }
                }
                foreach (string str2 in set)
                {
                    this._logger(string.Format(CultureInfo.CurrentCulture, Resources.BusinessLogicClass_Failed_Type_Load, new object[] { str2 }));
                }
            }
            return (from blc in this._contexts select blc.ContextData).ToArray<ContextData>();
        }

        public EntityData[] GetEntityDataItemsForContext(ContextData contextData)
        {
            BusinessLogicContext context = this._contexts[contextData.ID];
            List<BusinessLogicEntity> list = (context == null) ? new List<BusinessLogicEntity>() : context.Entities.ToList<BusinessLogicEntity>();
            return (from ble in list select ble.EntityData).ToArray<EntityData>();
        }

        internal void Initialize(Microsoft.VisualStudio.ServiceModel.DomainServices.Tools.BusinessLogicData businessLogicData)
        {
            this._businessLogicData = businessLogicData;
            if (businessLogicData.LinqToSqlPath != null)
            {
                LinqToSqlContext.OverrideAssemblyPath(businessLogicData.LinqToSqlPath);
            }
        }

        public bool IsMetadataGenerationRequired(ContextData contextData)
        {
            BusinessLogicContext context = this._contexts.SingleOrDefault<BusinessLogicContext>(c => c.ContextData.ID == contextData.ID);
            if (context == null)
            {
                return false;
            }
            return context.NeedToGenerateMetadataClasses;
        }

        private void LoadAssemblies(string[] assembliesToLoad, IList<Assembly> loadedAssemblies)
        {
            foreach (string str in assembliesToLoad)
            {
                Assembly item = AssemblyUtilities.LoadAssembly(str, this._logger);
                if (item != null)
                {
                    loadedAssemblies.Add(item);
                }
            }
        }

        void IRegisteredObject.Stop(bool immediate)
        {
        }

        private Microsoft.VisualStudio.ServiceModel.DomainServices.Tools.BusinessLogicData BusinessLogicData
        {
            get
            {
                if (this._businessLogicData == null)
                {
                    throw new InvalidOperationException(Resources.BusinessLogicClass_Not_Initialized);
                }
                return this._businessLogicData;
            }
        }

        internal string Language
        {
            get
            {
                return this.BusinessLogicData.Language;
            }
        }
    }
}

